/**
 * 
 */
package com.googlecode.pcapj;


import java.util.HashMap;

import org.bridj.Pointer;

import com.googlecode.pcapj.bridj.pcap_addr;
import com.googlecode.pcapj.bridj.sockaddr;

/**
 * 
 */
class SocketInfoImpl implements SocketInfo{
	private static final SocketAddressFactory<SocketAddress> defaultSocketAddressFactory = new SocketAddressFactory<SocketAddress>(){
		@Override
		SocketAddressImpl newSocketAddress(Pointer<sockaddr> sockaddr) {
			return new SocketAddressImpl(sockaddr);
		}
	};
	private static final HashMap<Integer, SocketAddressFactory<SocketAddress>> socketAddressFactoryMap = new HashMap<Integer, SocketAddressFactory<SocketAddress>>();  
	static{
		socketAddressFactoryMap.put(
				SocketFamily.AF_INET, 
				new SocketAddressFactory<SocketAddress>(){
					@Override
					SocketAddressImpl newSocketAddress(Pointer<sockaddr> sockaddr) {
						return new IPv4AddressImpl(sockaddr);
					}
				});
		
		socketAddressFactoryMap.put(
				SocketFamily.AF_INET6, 
				new SocketAddressFactory<SocketAddress>(){
					@Override
					SocketAddressImpl newSocketAddress(Pointer<sockaddr> sockaddr) {
						return new IPv6AddressImpl(sockaddr);
					}
				});
	}
	private int socketFamily;
	private SocketAddress address;
	private SocketAddress netmask;
	private SocketAddress broadcast;
	private SocketAddress destination;
	
	/**
	 * 
	 */
	SocketInfoImpl(pcap_addr pcap_addr) {
		super();
		address = newSockaddr(pcap_addr.addr());
		netmask = newSockaddr(pcap_addr.netmask());
		broadcast = newSockaddr(pcap_addr.broadaddr());
		destination = newSockaddr(pcap_addr.dstaddr());
		socketFamily = address.getSocketFamily();
	}
	private SocketAddress newSockaddr(Pointer<sockaddr> pointer){
		SocketAddress socketAddress = null;
		sockaddr sockaddr = getSockaddr(pointer);
		if(sockaddr != null){
			int family = sockaddr.sa_family() & 0xffff;
			SocketAddressFactory<SocketAddress> factory = socketAddressFactoryMap.get(family);
			if(factory == null){
				factory = defaultSocketAddressFactory;	
			}
			socketAddress = factory.newSocketAddress(pointer);
		}
		return socketAddress;
	}
	private sockaddr getSockaddr(Pointer<sockaddr> pointer){
		sockaddr sockaddr = null;
		if(pointer != Pointer.NULL){
			sockaddr = pointer.get();
		}
		return sockaddr;
	}
	/* (non-Javadoc)
	 * @see com.googlecode.pcapj.SocketInfo#getSocketFamily()
	 */
	public int getSocketFamily() {
		return socketFamily;
	}

	/* (non-Javadoc)
	 * @see com.googlecode.pcapj.SocketInfo#getAddress()
	 */
	public SocketAddress getAddress() {
		return address;
	}

	/* (non-Javadoc)
	 * @see com.googlecode.pcapj.SocketInfo#getNetmask()
	 */
	public SocketAddress getNetmask() {
		return netmask;
	}

	/* (non-Javadoc)
	 * @see com.googlecode.pcapj.SocketInfo#getBroadcast()
	 */
	public SocketAddress getBroadcast() {
		return broadcast;
	}

	/* (non-Javadoc)
	 * @see com.googlecode.pcapj.SocketInfo#getDestination()
	 */
	public SocketAddress getDestination() {
		return destination;
	}
	
}
